package com.diandi.messages.sign;


import com.diandi.messages.tools.Tools;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * <p>
 * 签名工具类
 * </p>
 * 
 * @author wanghui
 * @version $Id: SignUtil.java, v 0.1 2014-6-17 下午4:26:06 wanghui Exp $
 */
public class SignUtil {
	/**
	 * 签名
	 * 
	 * @param content
	 *            签名内容
	 * @param signMsg
	 *            网关返回签名           
	 * @param signType
	 *            MD5/RSA
	 * @param signKey
	 *            密钥
	 * @param charset
	 *            字符集
	 * @return
	 * @throws Exception
	 */
	public static boolean Check_sign(String content,String signMsg,String signType, String signKey,String charset) throws Exception {
		if ("MD5".equalsIgnoreCase(signType)) {
			return MD5.verify(content, signMsg, signKey, charset);
		} else if ("RSA".equalsIgnoreCase(signType)) {
			return RSA.verify(content, signMsg,signKey,charset);
		}
		return false;
	}

	public static String sign(String content, String signType, String signKey,
			String charset) throws Exception {
		if ("MD5".equalsIgnoreCase(signType)) {
			return MD5.sign(content, signKey, charset);
		} else if ("RSA".equalsIgnoreCase(signType)) {
			return RSA.sign(content, signKey, charset);
		}
		return "";
	}

	/**
	 * 加密参数的value值
	 * @param params   加密的参数集合
	 * @param sinaPublicKey   新浪公钥
	 * @return   加密后的集合
	 */
	public static Map<String,String> signParamsValue(Map<String,String> params,String sinaPublicKey) throws Exception{
		Map<String,String> signParams = new HashMap<String,String>();
		Iterator entries = params.entrySet().iterator();
		Map.Entry entry;
		String name = "";
		String value = "";
		String[] arr = Tools.get_need_RSA();//需要加密key的数组
		Arrays.sort(arr);
		while (entries.hasNext()) {
			entry = (Map.Entry) entries.next();
			name = (String) entry.getKey();
			if("sign_type".equals(name) || "sign_version".equals(name)){
				continue;
			}
			String valueObj = entry.getValue().toString();
			String base64_value_encrypt = null;
			if(null == valueObj){
				value = "";
			}else if(valueObj instanceof String){
				value = Tools.trimInnerSpaceStr(valueObj);
				//如果key在数组内则对其做加密(去除掉不用加签的加签类型和版本号)
				if (Arrays.binarySearch(arr, name)>=0) {
					byte[] value_encrypt = null;
					value_encrypt=RSA.encryptByPublicKey(value.getBytes("utf-8"), sinaPublicKey);
					base64_value_encrypt=Base64.encode(value_encrypt);
					//将加密好的value放到map中替换原有值
					signParams.put(name,base64_value_encrypt.toString());
				}else{
					value = valueObj.toString();
					signParams.put(name,value);
				}
			}
		}
		return signParams;
	}

	/**
	 * 根据参数生成新浪签名
	 * @param params     加签参数
	 * @param signKey    平台私钥
	 * @param charset    编码类型
	 * @return  签名值
	 * @throws Exception
	 */
	public static String signRSA(Map<String,String> params,String signKey,String charset) throws Exception{
		if(null == params && params.isEmpty()){
			return null;
		}
		// 生成待签名的字符串
		String content = Tools.createLinkString(params, false);
		return RSA.sign(content, signKey, charset);
	}



	/**
	 * 业务端及异步回调签名验证
	 * @param params
	 * @param charset
	 * @param sinaPublicKey
	 * @param signType
	 * @return
	 * @throws Exception
	 */
	public static Map<String,String> verifyBusinessCallBack(Map<String,String> params,String sinaPublicKey,String charset,String signType) throws Exception{
		String sign = params.get("sign").toString();
		if(StringUtils.isBlank(signType)) signType = params.get("sign_type").toString();// 签名方式
		if(StringUtils.isBlank(charset)) charset = params.get("_input_charset").toString();//编码格式
		params.remove("sign");
		params.remove("sign_type");
		params.remove("sign_version");
		String like_result = Tools.MapTransfStringByDecode(params,charset,true);
		if (SignUtil.Check_sign(like_result, sign,signType, sinaPublicKey, charset)){
			return params;
		} else {
			params.put("error","签名校验失败");
			return params;
		}
	}
	/**
	 * 业务端签名校验
	 * @param params
	 * @param charset
	 * @param sinaPublicKey
	 * @param signType
	 * @return
	 * @throws Exception
	 */
	/*public static Map<String,String> verifyBusinessParams(Map<String,String> params,String sinaPublicKey,String charset,String signType) throws Exception{
		String sign = params.get("sign").toString();
		if(StringUtils.isBlank(signType)) signType = params.get("sign_type").toString();// 签名方式
		params.remove("sign");
		params.remove("sign_type");
		params.remove("sign_version");
		String like_result = Tools.createLinkString(params, false);
		if (SignUtil.Check_sign(like_result, sign,signType, sinaPublicKey, charset)){
			return params;
		} else {
			params.put("error","签名校验失败");
			return params;
		}
	}*/

	/**
	 * 将敏感参数用新浪公钥进行RSA加密
	 * @param string
	 * @param sinaPublicKey
	 * @return
	 * @throws Exception
	 */
	public static String paramSignPublicKey(String string,String sinaPublicKey) throws Exception{
		byte[] bytes =  RSA.encryptByPublicKey(
				string.getBytes("utf-8"), sinaPublicKey);// RSA加密后的卡号
		return Base64.encode(bytes);
	}
}
